#include <pthread.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include "daq_thread.h"
#include "usr_typedef.h"
#include "adc_spd_uio.h"
#include "timet.h"
#include "eigenvalue_calc.h"
#include "math_statistics_func.h"
#include "led_gpio_ctl.h"
#include "file_save.h"
#include "calc_type.h"
#include "watchdog_thread.h"
#include "afe_init.h"
#include "zlog.h"
#include "afe_cmd.h"
#include "main.h"


#define SYS_MEM_DEV 				"/dev/mem"

#define ADS1672_UIO_DEV     		"/dev/uio0"
#define ADS1672_UIO_ADDR    		"/sys/class/uio/uio0/maps/map0/addr"
#define ADS1672_UIO_SIZE    		"/sys/class/uio/uio0/maps/map0/size"

#define SPEED_UIO_DEV       		"/dev/uio2"
#define SPEED_UIO_ADDR     	 		"/sys/class/uio/uio2/maps/map0/addr"
#define SPEED_UIO_SIZE      		"/sys/class/uio/uio2/maps/map0/size"

extern afe_dev_info 		afe1_dev;

pthread_mutex_t afe_data_mutex = PTHREAD_MUTEX_INITIALIZER;

void neon_memcpy(volatile     uint8_t *dst, volatile uint8_t *src, int sz);


//加速度原始数据内存拷贝
static void adc_data_memcpy(acc_unit acc_rt[], adc_handle *adc, 
									chx_cfg_info chx[], sys_cfg_info *sys)
{
	uint8_t ch;
	float sens[ACC_CH_TOTAL];
	uint32_t raw_volt_data_len = 0;

	raw_volt_data_len = (uint32_t)(sys->duration * sys->samp_freq);

	for (ch = 0; ch < ACC_CH_TOTAL; ch++) {	//由于ADC内部的FIR，前面一段数据不能用
		neon_memcpy((uint8_t *)acc_rt[ch].td_vdata_raw_volt, (uint8_t *)adc->adc_data_virt_addr + 
				(ch * AD_CHANNELX_OFFSET) + VDATA_RAW_OFFSET * sizeof(float), raw_volt_data_len * sizeof(float)); 
		sens[ch] = chx[ch].chx_pga_gain * chx[ch].chx_drcc_gain * chx[ch].chx_sens;

		/*
		printf("\n-------- ch = %d ----------------------------------------------------------------------------------------------------------------------\n", ch);
		for (int ii = 0; ii < 300; ii += 20)
		{
		
			printf("ii = %d %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n", ii,
				acc_rt[ch].td_vdata_raw_volt[ ii ], acc_rt[ch].td_vdata_raw_volt[ ii + 1], acc_rt[ch].td_vdata_raw_volt[ ii + 2], acc_rt[ch].td_vdata_raw_volt[ ii + 3], acc_rt[ch].td_vdata_raw_volt[ ii + 4],
				acc_rt[ch].td_vdata_raw_volt[ ii + 5 ], acc_rt[ch].td_vdata_raw_volt[ ii + 6], acc_rt[ch].td_vdata_raw_volt[ ii + 7], acc_rt[ch].td_vdata_raw_volt[ ii + 8], acc_rt[ch].td_vdata_raw_volt[ ii + 9],
				acc_rt[ch].td_vdata_raw_volt[ ii + 10], acc_rt[ch].td_vdata_raw_volt[ ii + 11], acc_rt[ch].td_vdata_raw_volt[ ii + 12], acc_rt[ch].td_vdata_raw_volt[ ii + 13], acc_rt[ch].td_vdata_raw_volt[ ii + 14],
				acc_rt[ch].td_vdata_raw_volt[ ii + 15], acc_rt[ch].td_vdata_raw_volt[ ii + 16], acc_rt[ch].td_vdata_raw_volt[ ii + 17], acc_rt[ch].td_vdata_raw_volt[ ii + 18], acc_rt[ch].td_vdata_raw_volt[ ii + 19]);
		}
		*/
		
		for (uint32_t j = 0; j < raw_volt_data_len; j++) {
			if (chx[ch].chx_mode != DC)
				*(acc_rt[ch].td_vdata_raw_g + j) = *(acc_rt[ch].td_vdata_raw_volt + j) / sens[ch];
		}
	}

	/*
	//for debug
	for (uint32_t j = 98030; j < 98060; j = j + 5)
		printf("%f %f %f %f %f\n", acc_rt[0].td_vdata_raw_g[j], acc_rt[0].td_vdata_raw_g[j + 1],
		acc_rt[0].td_vdata_raw_g[j + 2], acc_rt[0].td_vdata_raw_g[j + 3], acc_rt[0].td_vdata_raw_g[j + 4]);
	*/
}


//转速原始数据内存拷贝
static void speed_data_memcpy(sys_cfg_info *sys, speed_handle *pspd, spd_unit spdu[])
{
	uint32_t raw_size;

	raw_size = sys->samp_freq * sys->duration * sizeof(float);

	/*
	// for debug
	for (uint32_t m = 0; m < 50; m++)
	{
		printf("raw0 is %#x, raw1 is %#x\n", *(spdu[0].speed_pulse_raw + m), 
			*(spdu[1].speed_pulse_raw + m));
	}
	*/
	
	for (uint8_t ch = 0; ch < SPD_CH_TOTAL; ch++) {
		neon_memcpy(spdu[ch].speed_pulse_raw, (uint8_t *)pspd->spd_data_virt_addr + 
						(ch * SPD_CHANNELX_OFFSET), raw_size); 
	}
}

/*
static void afe_alert_check(sys_config *daq, chx_info *chx, const calc_norl calc[])
{
	unsigned char ch;

	for(ch = 0; ch < AFE_CH_TOTAL; ch++)
	{
		if(GET_REG_BIT(daq->daq_ch, ch) > 0) {
			if(calc[ch].td_rms_g > chx->chx_alarm[ch])
				chx->chx_status_alert[ch] = ALARM;
			if(calc[ch].td_rms_g > chx->chx_warning[ch])
				chx->chx_status_alert[ch] = WARNING;
		}
	}
}
*/


//加速度通道状态获取
void afe_chx_state_get(chx_cfg_info chx[], spd_cfg_info spd[], afe_dev_info *afe_dev)
{
	uint8_t afe_state[4];
	uint8_t spd_a24v, chx_a24v;
	uint8_t pga_ef, chx_plug;
	
	afe_get_state(afe_dev, afe_state);
	spd_a24v 	= afe_state[0] & 0x01;		// 低有效，低说明24V短路
	chx_a24v 	= afe_state[1];				// 低有效，低说明24V短路
	pga_ef 		= afe_state[2];				// 高有效，高说明超量程
	chx_plug	= afe_state[3];				// 高有效，高是传感器插入，低为拔出或短路或开路

	for (uint8_t i = 0; i < SPD_CH_TOTAL; i++)
	{
		if (spd_a24v == 1)
			spd[i].spd_a24v = A24V_NORMAL;
		else
			spd[i].spd_a24v = A24V_ERROR;
	}

	for (uint8_t ch = 0; ch < ACC_CH_TOTAL; ch++)
    {
        if (GET_REG_BIT(chx_a24v, ch))
			chx[ch].chx_pwr_a24v = A24V_NORMAL;
        else
			chx[ch].chx_pwr_a24v = A24V_ERROR;

		if (GET_REG_BIT(pga_ef, ch))
			chx[ch].chx_pga_ef = EF_ERROR;
        else
			chx[ch].chx_pga_ef = EF_NORMAL;

		if (GET_REG_BIT(chx_plug, ch))
			chx[ch].chx_plug_det = INSERTED;
        else
			chx[ch].chx_plug_det = REMOVED;
    }
	
}


//加速度通道数据采集、计算、存储线程
void *daq_acc_thread(void *arc)
{
    char adc_uio_addr_buf[18], adc_uio_size_buf[18];
	char spd_uio_addr_buf[18], spd_uio_size_buf[18];
	int sys_mem_fd;
    int adc_uio_fd, adc_addr_fd, adc_size_fd;
	int spd_uio_fd, spd_addr_fd, spd_size_fd;
	//float spd0_coeff = 1.0, spd1_coeff = 1.0;
	int data_save_inv = 0;
	int irq_on = 0;

	thread_status *s = NULL;

	if (arc == NULL)
		return NULL;

	s = (thread_status*)arc;
	s->status = TS_READY;
	printf("accelerated data acquisition thread is starting!\n");

	sys_mem_fd 	= open(SYS_MEM_DEV, O_RDWR | O_SYNC);
	
    adc_uio_fd 	= open(ADS1672_UIO_DEV, O_RDWR);
    adc_addr_fd = open(ADS1672_UIO_ADDR, O_RDONLY);
    adc_size_fd = open(ADS1672_UIO_SIZE, O_RDONLY);
	if(adc_addr_fd < 0 || adc_size_fd < 0 || adc_uio_fd < 0 || sys_mem_fd < 0) {
		dzlog_error("daq adc uio device file open error!");
		perror("daq adc uio device file open error!");
        exit(EXIT_FAILURE);
    }

	spd_uio_fd 	= open(SPEED_UIO_DEV, O_RDWR);
    spd_addr_fd = open(SPEED_UIO_ADDR, O_RDONLY);
    spd_size_fd = open(SPEED_UIO_SIZE, O_RDONLY);
	if(spd_addr_fd < 0 || spd_size_fd < 0 || spd_uio_fd < 0 || sys_mem_fd < 0) {
		dzlog_error("daq spd uio device file open error!");
		perror("daq spd uio device file open error!");
        exit(EXIT_FAILURE);
    }

	read(adc_addr_fd, adc_uio_addr_buf, sizeof(adc_uio_addr_buf));
    read(adc_size_fd, adc_uio_size_buf, sizeof(adc_uio_size_buf));
	read(spd_addr_fd, spd_uio_addr_buf, sizeof(spd_uio_addr_buf));
    read(spd_size_fd, spd_uio_size_buf, sizeof(spd_uio_size_buf));

    adc_dev.mem_uio_fd = sys_mem_fd;
	spd_dev.mem_uio_fd = sys_mem_fd;
	
	adc_dev.adc_axi_uio_fd = adc_uio_fd;
    adc_dev.adc_axi_base_addr = strtoul(adc_uio_addr_buf, NULL, 16);	//16代表16进制读取
    //adc_dev.adc_axi_addr_size = strtoul(adc_uio_size_buf, NULL, 16);
    adc_dev.adc_axi_addr_size = 0x10000;								//64K固定地址空间

	spd_dev.spd_axi_uio_fd = spd_uio_fd;
	spd_dev.spd_axi_base_addr = strtoul(spd_uio_addr_buf, NULL, 16);
    //spd_dev.spd_axi_addr_size = strtoul(spd_uio_size_buf, NULL, 16);
	spd_dev.spd_axi_addr_size = 0x10000;								//64K固定地址空间
	
	if (sys_cfg.debug == ON) {
	    printf("mem_uio_fd is %d\n", adc_dev.mem_uio_fd);
		printf("adc_axi_uio_fd is %d\n", adc_dev.adc_axi_uio_fd);
		printf("adc_axi_base_addr is %#x\n", adc_dev.adc_axi_base_addr);
		printf("adc_axi_addr_size is %#x\n", adc_dev.adc_axi_addr_size);

		printf("spd_axi_uio_fd is %d\n", spd_dev.spd_axi_uio_fd);
		printf("spd_axi_base_addr is %#x\n", spd_dev.spd_axi_base_addr);
		printf("spd_axi_addr_size is %#x\n", spd_dev.spd_axi_addr_size);
	}
	adc_mmap_setup(&adc_dev, AD_DATA_CHANNEL_BASE);
	speed_mmap_setup(&spd_dev, SPD_DATA_CHANNEL_BASE);
	
	/*模拟前端各通道模式配置*/
	afe_mode_config(&sys_cfg, &afe1_dev, chx_cfg, spd_cfg);

	sleep(1);
	adc_init(&sys_cfg, &adc_dev, chx_cfg);

	spd_rt[0].speed_coeff = spd_cfg[0].spd_pulse * ((float)(adc_dev.irq_cnt * PING_PANG_FIFO_SIZE) / sys_cfg.samp_freq);
	spd_rt[1].speed_coeff = spd_cfg[1].spd_pulse * ((float)(adc_dev.irq_cnt * PING_PANG_FIFO_SIZE) / sys_cfg.samp_freq);

	printf("spd_cfg[0].spd_pulse is %f, spd_rt[0].speed_coeff is %f\n", spd_cfg[0].spd_pulse, spd_rt[0].speed_coeff);
	printf("spd_cfg[1].spd_pulse is %f, spd_rt[1].speed_coeff is %f\n", spd_cfg[1].spd_pulse, spd_rt[1].speed_coeff);

    irq_on = 1;
    write(adc_dev.adc_axi_uio_fd, &irq_on, 0x04); 					// 开UIO中断

	while(s->status && (read(adc_dev.adc_axi_uio_fd, &adc_dev.irq_flag, 0x04) == 0x04)) {
		if (sys_cfg.debug == ON)
			printf("#########%s uio interrupt number is %d#########\n", ADS1672_UIO_DEV, adc_dev.irq_flag);

        adc_axi_reg_set(&adc_dev, ADS1672_REG3_OFFSET, 0x01); 			//清FPGA中断，必须
        adc_axi_reg_set(&adc_dev, ADS1672_REG0_OFFSET, 0x00); 			//非连续采集需要停止

		led_daq_stop();
		
		//得到RPM转速值
		spd_rt[0].speed_val = ((float)(speed_axi_reg_get(&spd_dev, SPEED_REG2_OFFSET) - 1) / spd_rt[0].speed_coeff) * 60.0;	//转换成RPM
		spd_rt[1].speed_val = ((float)(speed_axi_reg_get(&spd_dev, SPEED_REG3_OFFSET) - 1) / spd_rt[1].speed_coeff) * 60.0;	//转换成RPM
		if (spd_cfg[0].spd_mode == MAGN) {
			spd_rt[0].speed_val = spd_rt[0].speed_val / 2.0f;
			spd_rt[1].speed_val = spd_rt[1].speed_val / 2.0f;
		}
		printf("speed_axi_reg_get(&spd_dev, SPEED_REG2_OFFSET) is %d\n", speed_axi_reg_get(&spd_dev, SPEED_REG2_OFFSET));
		printf("speed_axi_reg_get(&spd_dev, SPEED_REG3_OFFSET) is %d\n", speed_axi_reg_get(&spd_dev, SPEED_REG3_OFFSET));

		afe_chx_state_get(chx_cfg, spd_cfg, &afe1_dev);
		
		pthread_mutex_lock(&afe_data_mutex);

		//数据拷贝
		adc_data_memcpy(acc_rt, &adc_dev, chx_cfg, &sys_cfg);
		speed_data_memcpy(&sys_cfg, &spd_dev, spd_rt);

		if (sys_cfg.debug == ON) {
			printf("spd_raw[0].speed_val is %f, spd_raw[1].speed_val is %f\n", spd_rt[0].speed_val, spd_rt[1].speed_val);
		}

		acc_td_eigenvalue_calc(&sys_cfg, acc_rt, chx_cfg);							//时域特征值计算
		//acc_fd_unif_time_calc(&sys_cfg, acc_rt, chx_cfg, spd_rt);					//等时采样特征值计算
		//acc_fd_unif_angle_calc(&sys_cfg, spd_cfg, spd_rt, acc_rt, chx_cfg);		//等角采样特征值计算

		pthread_mutex_unlock(&afe_data_mutex);

		data_save_inv = data_save_inv + sys_cfg.duration + sys_cfg.daq_thd_slp;

		//有足够硬盘空间，转速大于阈值，则保存数据，自动测试时使用
		if (data_save_inv >= (sys_cfg.disk_data_save_inv)) {
			data_save_inv = 0;
			if ((sys_rt.disk_chk_flag == 0) && ((spd_rt[0].speed_val >= spd_cfg[0].spd_save_thrd) || 
					(spd_rt[1].speed_val >= spd_cfg[1].spd_save_thrd)))
				vdata_file_save(&sys_cfg, &sys_rt, chx_cfg, acc_rt, spd_cfg, spd_rt);
		}
		
		/*
		watchdog_feed(&wdt_dev);											// 喂狗
		if (sys_cfg.debug == ON)
			printf("watchdog feed on acc data acquisition thread!\n");
		*/

		if(s->status == TS_ALIVE) {
			irq_on = 1;
			sleep(sys_cfg.daq_thd_slp);
	    	write(adc_dev.adc_axi_uio_fd, &irq_on, 0x04);   				// 从新开始UIO中断 必须
        	adc_axi_reg_set(&adc_dev, ADS1672_REG0_OFFSET, 0xFF); 			// 非连续采集需要从新开始
        	led_daq_in_process();
		}
	}

	dzlog_notice("accelerated data acquisition thread exit!!!");
	printf("accelerated data acquisition thread exit!!!\n");
	s->status = TS_TERMINATED;
	pthread_exit(arc);
}
